import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class LexAnalysis {
	private String[] keyWords = {
		"begin", "end", "if", "then", "else", "const", "procedure", "var", "do", "while", "call", "read", "write", "odd", "repeat", "until"
	};

	private List<Token> allToken; 
	private char ch = ' ';       
	private int sp = 0;   
	private char[] yourCode;     
	private int lineNumber = 1;        
	private String tokenStr;    
	/**
	 * 词法分析输入源文件首先将文件源代码读入缓冲区buffer,再进行词法分析doAnalysis
	 * @param file
	 */
	public LexAnalysis(File file) {
		init(); 
		
		BufferedReader bf = null;
        try {
            bf = new BufferedReader(new FileReader(file));
            String temp1 = "", temp2 = "";
            while((temp1 = bf.readLine()) != null) {
                temp2 = temp2 + temp1 + String.valueOf('\n');
            }
            yourCode = temp2.toCharArray();
            bf.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //进行词法分析，直到缓冲区没有要分析的字符
        while (sp < yourCode.length) {
         	allToken.add(analysis());
        }
	}
	
	public List<Token> getAllToken() {
        return allToken;
    }

	private Token analysis() {
		tokenStr = "";
		getChar();
        while ((ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0') && sp < yourCode.length) {
            if (ch == '\n') {
                lineNumber++;
            }
            getChar();
        }
        if (ch == '$' && sp >= yourCode.length) { 
            return new Token(Token.SymType.EOF, lineNumber, "-1");
        }
        if (Character.isLetter(ch)) {
        	while (Character.isLetter(ch) || Character.isDigit(ch)) {
                tokenStr += ch;
                getChar();
            }
            ch = ' ';
        	sp--;
            for (int i = 0; i < keyWords.length; i++) {
                if (tokenStr.equals(keyWords[i])) { 
                    return new Token(Token.SymType.values()[i], lineNumber, "-");
                }
            }
            return new Token(Token.SymType.SYM, lineNumber, tokenStr);
        } else if (Character.isDigit(ch)) { 
        	while (Character.isDigit(ch)) {
                tokenStr += ch;
                getChar();
            }
            ch = ' ';
        	sp--;
            return new Token(Token.SymType.CONST, lineNumber, tokenStr);
        } else if (ch == '=') { 
            return new Token(Token.SymType.EQU, lineNumber, "-");
        } else if (ch == '+') { 
            return new Token(Token.SymType.ADD, lineNumber, "-");
        } else if (ch == '-') { 
            return new Token(Token.SymType.SUB, lineNumber, "-");
        } else if (ch == '*') { 
            return new Token(Token.SymType.MUL, lineNumber, "-");
        } else if (ch == '/') { 
            return new Token(Token.SymType.DIV, lineNumber, "-");
        } else if (ch == '<') { 
            getChar();
            if (ch == '=') {
                return new Token(Token.SymType.LESE, lineNumber, "-");
            } else if (ch == '>') {
                return new Token(Token.SymType.NEQE, lineNumber, "-");
            } else {
                ch = ' ';
            	sp--;
                return new Token(Token.SymType.LES, lineNumber, "-");
            }
        } else if (ch == '>') { 
            getChar();
            if (ch == '=') {
                return new Token(Token.SymType.LARE, lineNumber, "-");
            } else {
                ch = ' ';
            	sp--;
                return new Token(Token.SymType.LAR, lineNumber, "-");
            }
        } else if (ch == ',') { 
            return new Token(Token.SymType.COMMA, lineNumber, "-");
        } else if (ch == ';') { 
            return new Token(Token.SymType.SEMIC, lineNumber, "-");
        } else if (ch == '.') { 
            return new Token(Token.SymType.POI, lineNumber, "-");
        } else if (ch == '(') { 
            return new Token(Token.SymType.LBR, lineNumber, "-");
        } else if (ch == ')') { 
            return new Token(Token.SymType.RBR, lineNumber, "-");
        } else if (ch == ':') { 
            getChar();
            if (ch == '=') {
                return new Token(Token.SymType.CEQU, lineNumber, "-");
            } else {
            	ch = ' ';
            	sp--;
            	return new Token(Token.SymType.COL, lineNumber, "-");
            }
        }
        return new Token(Token.SymType.EOF, lineNumber, "-");
	}

	private void init() {
		allToken = new ArrayList<Token>();
	}

	private char getChar() {
		if (sp < yourCode.length) {
			ch = yourCode[sp];
			sp++;
		} else {
			ch = '$';
		}
		return ch;
	}
}
